using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using ICSharpCode.TextEditor.Actions;
using ICSharpCode.TextEditor.Document;
using ICSharpCode.TextEditor.Properties;
using ICSharpCode.TextEditor.Src.Actions;
using ICSharpCode.TextEditor.Src.Document.FoldingStrategy;
using ICSharpCode.TextEditor.Src.Document.HighlightingStrategy.SyntaxModes;
using ICSharpCode.TextEditor.UserControls;

namespace ICSharpCode.TextEditor
{
	[ToolboxBitmap("ICSharpCode.TextEditor.Resources.TextEditorControl.bmp")]
	[ToolboxItem(true)]
	public class TextEditorControlEx : TextEditorControl
	{
		private bool _contextMenuEnabled;

		private bool _contextMenuShowDefaultIcons;

		private bool _contextMenuShowShortCutKeys;

		private readonly FindAndReplaceForm _findForm = new FindAndReplaceForm();

		private string _foldingStrategy;

		private string _syntaxHighlighting;

		public string SelectedText => this.ActiveTextAreaControl.SelectionManager.SelectedText;

		public string[] Lines => base.Text.Split(new string[1] { "\r\n" }, StringSplitOptions.None);

		[Browsable(false)]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
		public new IDocument Document
		{
			get
			{
				return base.document;
			}
			set
			{
				if (value == null)
				{
					throw new ArgumentNullException("value");
				}
				if (base.document != null)
				{
					base.document.DocumentChanged -= base.OnDocumentChanged;
					base.document.DocumentChanged -= OnDocumentChangedDoUpdateContextMenu;
				}
				base.document = value;
				base.document.UndoStack.TextEditorControl = this;
				base.document.DocumentChanged += base.OnDocumentChanged;
				base.document.DocumentChanged += OnDocumentChangedDoUpdateContextMenu;
			}
		}

		[Browsable(true)]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
		[DefaultValue(typeof(Font), null)]
		[Description("The base font of the text area. No bold or italic fonts can be used because bold/italic is reserved for highlighting purposes.")]
		public override Font Font
		{
			get
			{
				return this.Document.TextEditorProperties.Font;
			}
			set
			{
				this.Document.TextEditorProperties.Font = value;
				this.OptionsChanged();
			}
		}

		[Category("Appearance")]
		[DefaultValue(false)]
		[Description("Hide the vertical ScrollBar if it's not needed. ")]
		public bool HideVScrollBarIfPossible { get; set; }
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [Category("Appearance")]
		[Description("Set the Folding Strategy. Supported : XML and CSharp.")]
		public string FoldingStrategy
		{
			get
			{
				return this._foldingStrategy;
			}
			set
			{
				this.SetFoldingStrategy(value);
				this.OptionsChanged();
			}
		}
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [Category("Appearance")]
		[Description("Sets the Syntax Highlighting.")]
		public string SyntaxHighlighting
		{
			get
			{
				return this._syntaxHighlighting;
			}
			set
			{
				this._syntaxHighlighting = value;
				this.SetHighlighting(this._syntaxHighlighting);
				this.OptionsChanged();
			}
		}

		[Category("Behavior")]
		[DefaultValue(false)]
		[Description("If true document is readonly.")]
		[Browsable(true)]
		public new bool IsReadOnly
		{
			get
			{
				return this.Document.ReadOnly;
			}
			set
			{
				this.Document.ReadOnly = value;
				this.OptionsChanged();
			}
		}

		[DefaultValue(false)]
		[Category("Appearance")]
		[Description("Show default Icons in ContextMenu")]
		[Browsable(true)]
		public bool ContextMenuShowDefaultIcons
		{
			get
			{
				return this._contextMenuShowDefaultIcons & this._contextMenuEnabled;
			}
			set
			{
				this._contextMenuShowDefaultIcons = this._contextMenuEnabled && value;
			}
		}

		[DefaultValue(false)]
		[Category("Appearance")]
		[Description("Show shortcut keys in ContextMenu")]
		[Browsable(true)]
		public bool ContextMenuShowShortCutKeys
		{
			get
			{
				return this._contextMenuShowShortCutKeys & this._contextMenuEnabled;
			}
			set
			{
				this._contextMenuShowShortCutKeys = this._contextMenuEnabled && value;
			}
		}

		[DefaultValue(false)]
		[Category("Appearance")]
		[Description("Enable a ContextMenu")]
		[Browsable(true)]
		public bool ContextMenuEnabled
		{
			get
			{
				return this._contextMenuEnabled;
			}
			set
			{
				this._contextMenuEnabled = value;
			}
		}

		public TextEditorControlEx()
		{
			base.editactions[Keys.F | Keys.Control] = new EditFindAction(this._findForm, this);
			base.editactions[Keys.H | Keys.Control] = new EditReplaceAction(this._findForm, this);
			base.editactions[Keys.F3] = new FindAgainAction(this._findForm, this);
			base.editactions[Keys.F3 | Keys.Shift] = new FindAgainReverseAction(this._findForm, this);
			base.editactions[Keys.G | Keys.Control] = new GoToLineNumberAction();
			HighlightingManager.Manager.AddSyntaxModeFileProvider(new ResourceSyntaxModeProviderEx());
			base.TextChanged += TextChangedEventHandler;
		}

		protected override void OnLoad(EventArgs e)
		{
			if (this.ContextMenuEnabled)
			{
				this.AssignContextMenu(this.CreateNewContextMenu(this.ContextMenuShowDefaultIcons, this.ContextMenuShowShortCutKeys));
			}
			base.OnLoad(e);
		}

		protected override void Dispose(bool disposing)
		{
			base.Dispose(disposing);
			base.TextChanged -= TextChangedEventHandler;
		}

		private void TextChangedEventHandler(object sender, EventArgs e)
		{
			TextEditorControlEx textEditorControlEx = sender as TextEditorControlEx;
			if (textEditorControlEx != null)
			{
				bool flag = textEditorControlEx.Document.TotalNumberOfLines > this.ActiveTextAreaControl.TextArea.TextView.VisibleLineCount;
				if (this.ActiveTextAreaControl.VScrollBar.Visible && this.HideVScrollBarIfPossible && !flag)
				{
					this.ActiveTextAreaControl.ShowScrollBars(Orientation.Vertical, isVisible: false);
				}
			}
		}

		public void SetTextAndRefresh(string text, bool updateFoldings = false)
		{
			this.ResetText();
			this.Text = text;
			if (updateFoldings && this.Document.TextEditorProperties.EnableFolding)
			{
				this.Document.FoldingManager.UpdateFoldings(null, null);
			}
			this.Refresh();
		}

		public void SetFoldingStrategy(string foldingStrategy)
		{
			if (foldingStrategy == null)
			{
				throw new ArgumentNullException("foldingStrategy");
			}
			if (!this.Document.TextEditorProperties.EnableFolding)
			{
				return;
			}
			if (!(foldingStrategy == "XML"))
			{
				if (foldingStrategy == "CSharp")
				{
					this._foldingStrategy = foldingStrategy;
					this.Document.FoldingManager.FoldingStrategy = new CSharpFoldingStrategy();
				}
				else
				{
					this.Document.FoldingManager.FoldingStrategy = null;
					this._foldingStrategy = null;
				}
			}
			else
			{
				this._foldingStrategy = foldingStrategy;
				this.Document.FoldingManager.FoldingStrategy = new XmlFoldingStrategy();
			}
			this.Document.FoldingManager.UpdateFoldings(null, null);
		}

		public List<string> GetFoldingErrors()
		{
			if (this._foldingStrategy == "XML")
			{
				IFoldingStrategyEx foldingStrategyEx = this.Document.FoldingManager.FoldingStrategy as IFoldingStrategyEx;
				if (foldingStrategyEx != null)
				{
					return foldingStrategyEx.GetFoldingErrors();
				}
			}
			return new List<string>();
		}

		private bool CanUndo()
		{
			return this.Document.UndoStack.CanUndo;
		}

		private bool CanRedo()
		{
			return this.Document.UndoStack.CanRedo;
		}

		private bool CanCopy()
		{
			return this.ActiveTextAreaControl.SelectionManager.HasSomethingSelected;
		}

		private bool CanCut()
		{
			return this.ActiveTextAreaControl.SelectionManager.HasSomethingSelected;
		}

		private bool CanDelete()
		{
			return this.ActiveTextAreaControl.SelectionManager.HasSomethingSelected;
		}

		private bool CanPaste()
		{
			return this.ActiveTextAreaControl.TextArea.ClipboardHandler.EnablePaste;
		}

		private bool CanSelectAll()
		{
			if (this.Document.TextContent == null)
			{
				return false;
			}
			return !this.Document.TextContent.Trim().Equals(string.Empty);
		}

		private bool CanFind()
		{
			if (this.Document.TextContent == null)
			{
				return false;
			}
			return this.Document.TextContent.Trim().Any();
		}

		protected void DoCut()
		{
			new Cut().Execute(this.ActiveTextAreaControl.TextArea);
			this.ActiveTextAreaControl.Focus();
		}

		protected void DoDelete()
		{
			new Delete().Execute(this.ActiveTextAreaControl.TextArea);
			this.ActiveTextAreaControl.Focus();
		}

		protected void DoCopy()
		{
			new Copy().Execute(this.ActiveTextAreaControl.TextArea);
			this.ActiveTextAreaControl.Focus();
		}

		protected void DoPaste()
		{
			new Paste().Execute(this.ActiveTextAreaControl.TextArea);
			this.ActiveTextAreaControl.Focus();
		}

		private void DoSelectAll()
		{
			new SelectWholeDocument().Execute(this.ActiveTextAreaControl.TextArea);
			this.ActiveTextAreaControl.Focus();
		}

		public void DoToggleFoldings()
		{
			new ToggleAllFoldings().Execute(this.ActiveTextAreaControl.TextArea);
		}

		private void DoFind()
		{
			new EditFindAction(this._findForm, this).Execute(this.ActiveTextAreaControl.TextArea);
		}

		private ContextMenuStrip CreateNewContextMenu(bool showImages, bool showKeys)
		{
			ContextMenuStripEx contextMenuStripEx = new ContextMenuStripEx();
			contextMenuStripEx.AddToolStripMenuItem("&Undo", showImages ? Resources.sc_undo : null, delegate
			{
				base.Undo();
			}, showKeys ? (Keys.Z | Keys.Control) : Keys.None, CanUndo);
			contextMenuStripEx.AddToolStripMenuItem("&Redo", showImages ? Resources.sc_redo : null, delegate
			{
				base.Redo();
			}, showKeys ? (Keys.Y | Keys.Control) : Keys.None, CanRedo);
			contextMenuStripEx.AddToolStripSeparator();
			contextMenuStripEx.AddToolStripMenuItem("&Cut", showImages ? Resources.cut : null, delegate
			{
				this.DoCut();
			}, showKeys ? (Keys.X | Keys.Control) : Keys.None, CanCut);
			contextMenuStripEx.AddToolStripMenuItem("Cop&y", showImages ? Resources.sc_copy : null, delegate
			{
				this.DoCopy();
			}, showKeys ? (Keys.C | Keys.Control) : Keys.None, CanCopy);
			contextMenuStripEx.AddToolStripMenuItem("&Paste", showImages ? Resources.sc_paste : null, delegate
			{
				this.DoPaste();
			}, showKeys ? (Keys.V | Keys.Control) : Keys.None, CanPaste);
			contextMenuStripEx.AddToolStripSeparator();
			contextMenuStripEx.AddToolStripMenuItem("&Delete", showImages ? Resources.sc_cancel : null, delegate
			{
				this.DoDelete();
			}, showKeys ? Keys.Delete : Keys.None, CanDelete);
			contextMenuStripEx.AddToolStripMenuItem("&Select All", showImages ? Resources.sc_selectall : null, delegate
			{
				this.DoSelectAll();
			}, showKeys ? (Keys.A | Keys.Control) : Keys.None, CanSelectAll);
			contextMenuStripEx.AddToolStripMenuItem("&Find", showImages ? Resources.sc_searchdialog : null, delegate
			{
				this.DoFind();
			}, showKeys ? (Keys.F | Keys.Control) : Keys.None, CanFind);
			return contextMenuStripEx;
		}

		private void AssignContextMenu(ContextMenuStrip mnu)
		{
			if (this.ActiveTextAreaControl.ContextMenuStrip != null)
			{
				this.ActiveTextAreaControl.ContextMenuStrip.Dispose();
				this.ActiveTextAreaControl.ContextMenuStrip = null;
			}
			this.ActiveTextAreaControl.ContextMenuStrip = mnu;
		}

		public void SelectText(int start, int length)
		{
			int textLength = this.Document.TextLength;
			if (textLength < start + length)
			{
				length = textLength - 1 - start;
			}
			this.ActiveTextAreaControl.Caret.Position = this.Document.OffsetToPosition(start + length);
			this.ActiveTextAreaControl.SelectionManager.ClearSelection();
			this.ActiveTextAreaControl.SelectionManager.SetSelection(new DefaultSelection(this.Document, this.Document.OffsetToPosition(start), this.Document.OffsetToPosition(start + length)));
			this.Refresh();
		}

		private void OnDocumentChangedDoUpdateContextMenu(object sender, DocumentEventArgs e)
		{
			bool visible = this.Document.TotalNumberOfLines > this.ActiveTextAreaControl.TextArea.TextView.VisibleLineCount;
			this.ActiveTextAreaControl.VScrollBar.Visible = visible;
		}
	}
}
